//Package session implements basic session handling to use with database
package session

import (
	"crypto/rand"
	"net/http"
	"time"
	"fmt"
)

type Session struct {
	Id  string
	rsp http.ResponseWriter
}

//Cookie name
var Name = "SESSID"

//Start(rsp http.ResponseWriter, req *http.Request) (*Session, error)
//reads session ID from cookie
//generates new if none stored
func Start(rsp http.ResponseWriter, req *http.Request) (*Session, error) {
	sess := new(Session)
	sess.rsp = rsp
	rid, _ := req.Cookie(Name)
	if rid != nil && rid.Value != "" {
		sess.Id = rid.Value
	} else {
		err := sess.generateId()
		if err != nil {
			return nil, err
		}
	}

	exp := time.Now().Add(time.Hour * 24).Format(time.RFC1123)
	cook := fmt.Sprintf("%s=%s; path=/; expires=%s;", Name, sess.Id, exp)
	if rid == nil && rid.Value != "" {
		rsp.Header().Add("Set-Cookie", cook)
	} else {
		rsp.Header().Set("Set-Cookie", cook)
	}
	
	return sess, nil
}

//End()
//Clear session
func (this *Session) End() {
	this.rsp.Header().Set("Set-Cookie", fmt.Sprintf("%s=; path=/;", Name))
}

//RegenerateId() error
//Make new ID for the same session
func (this *Session) RegenerateId() error {
	err := this.generateId()
	if err != nil {
		return err
	}
	exp := time.Now().Add(time.Hour * 24).Format(time.RFC1123)
	this.rsp.Header().Set("Set-Cookie", fmt.Sprintf("%s=%s; path=/; expires=%s;", Name, this.Id, exp))
	return nil
}

func (this *Session) generateId() error {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		return err
	}
	this.Id = fmt.Sprintf("%x", b)
	return nil	
}


/*
func (this *Session) Get(name string) val, error {
	val, exist := content[this.Id]
	if exist {
		ret = val
	}
	return
}

func (this *Session) Set(val int) {
	content[this.Id] = val
}

//Upload session to DB
func (this *Session) Store() error {
}

//Upload session to DB
func (this *Session) Load() error {
}
/**/